#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/gpio/consumer.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/i2c.h>
#include <asm/unaligned.h>
/*
*	触摸屏驱动步骤：
*	1、描述i2c设备结构体
*	2、注册i2c设备
*	3、读取设备树获得引脚信息、中断号
*	4、申请中断、注册中断处理函数
*	5、申请input设备
*	6、注册input子设备
*/

#define GT_CTRL_REG 	        0X8040  /*  gt9271控制寄存器       */
#define GT_MODSW_REG 	        0X804D  /*  gt9271模式切换寄存器    */
#define GT_9271_CFGS_REG 	    0X8047  /*  gt9271配置起始地址寄存器 */
#define GT_CHECK_REG 	        0X80FF  /*  gt9271校验和寄存器      */
#define GT_PID_REG 		        0X8140  /*  gt9271产品ID寄存器      */
#define GT_GSTID_REG 	        0X814E  /* gt9271当前检测到的触摸情况 */


/*	每组八个寄存器
*	第一个寄存器用于标记触摸点id
*	2～5四个寄存器用于存储触摸点坐标
*	6、7两个寄存器用于存储触摸点尺寸	
*	最后一个寄存器保留
*	此外读取寄存器时，GT9271地址自增
*/
#define GT_TP1_REG 		        0X814F  /* 第一个触摸点数据地址 */
#define GT_TP2_REG 		        0X8157	/* 第二个触摸点数据地址 */
#define GT_TP3_REG 		        0X815F  /* 第三个触摸点数据地址 */
#define GT_TP4_REG 		        0X8167  /* 第四个触摸点数据地址 */
#define GT_TP5_REG 		        0X816F	/* 第五个触摸点数据地址 */
#define GT_TP6_REG 		        0X8177	/* 第六个触摸点数据地址 */
#define GT_TP7_REG 		        0X817F	/* 第七个触摸点数据地址 */
#define GT_TP8_REG 		        0X8187	/* 第八个触摸点数据地址 */
#define GT_TP9_REG 		        0X818F	/* 第九个触摸点数据地址 */
#define GT_TP10_REG 		    0X8197	/* 第十个触摸点数据地址 */
#define MAX_SUPPORT_POINTS      10      /* 最多10点电容触摸 */
#define GT9271_REG_READLEN		4       /*连续读取的寄存器数*/

/*GT9271设备描述结构体*/
typedef struct Gt9271Device {
	int iIrqPin;							/* 中断IO			*/
	int iResetPin;							/* 复位IO			*/
	int iIrqNum;							/* 中断号    		*/
	int iIrqType;							/* 中断类型         */
	int iXMax;								/* 最大横坐标   	*/
	int iYMax; 								/* 最大纵坐标		*/
	int iTouchNum;							/* 输出触点最大数量  */
	void *PrivateData;						/* 私有数据 		*/
	struct input_dev *ptInput;				/* input结构体 		*/
	struct i2c_client *ptClientIIC;			/* I2C客户端 		*/
}T_Gt9271Device,*PT_Gt9271Device;

static T_Gt9271Device g_tGt9271;

const unsigned char ucIrqTable[] = {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH};  /* 触发方式 */


/*写多个寄存器*/
static int WriteMultiReg(PT_Gt9271Device ptGt9271Device,unsigned short ucRegAddr,unsigned char *pucData,unsigned int iLength)
{
	int iError;
	unsigned char *pucbuffer = (unsigned char *)kmalloc(sizeof(unsigned char)*(iLength+2),GFP_KERNEL);
	struct i2c_msg msg;
	struct i2c_client* ptClient = (struct i2c_client *)ptGt9271Device->ptClientIIC;

	pucbuffer[0] = ucRegAddr >> 8;		/* 寄存器首地址低8位 */	
	pucbuffer[1] = ucRegAddr & 0XFF;	/* 寄存器首地址高8位 */
	memcpy(&pucbuffer[2],pucData,iLength);

	msg.addr  = ptClient->addr;
	msg.flags = 0;
	msg.buf   = pucbuffer;
	msg.len   = iLength+2;

	iError = i2c_transfer(ptClient->adapter, &msg, 1);

	kfree(pucbuffer);

	return iError;
}
/*读多个寄存器*/
static int ReadMultiReg(PT_Gt9271Device ptGt9271Device,unsigned short ucRegAddr,unsigned char *pucData,int iLength)
{
	int iError;
	unsigned char pucbuffer[2];
	struct i2c_msg msg[2];
	struct i2c_client* ptClient = (struct i2c_client *)ptGt9271Device->ptClientIIC;

	pucbuffer[0] = ucRegAddr >> 8;		/* 寄存器首地址低8位 */	
	pucbuffer[1] = ucRegAddr & 0XFF;	/* 寄存器首地址高8位 */

	/* msg[0]为发送要读取的首地址 */
	msg[0].addr = ptClient->addr;		/* ft5x06地址 */
	msg[0].flags = !I2C_M_RD;			/* 标记为发送数据 */
	msg[0].buf = pucbuffer;			/* 读取的首地址 */
	msg[0].len = 2;						/* reg长度*/

	/* msg[1]读取数据 */
	msg[1].addr = ptClient->addr;			/* ft5x06地址 */
	msg[1].flags = I2C_M_RD;			/* 标记为读取数据*/
	msg[1].buf = pucData;					/* 读取数据缓冲区 */
	msg[1].len = iLength;					/* 要读取的数据长度*/

	iError = i2c_transfer(ptClient->adapter, msg, 2);
	if(iError == 2) iError = 0;
	return iError;
}
static int ReadFirmware(PT_Gt9271Device ptGt9271Device)
{
	int iError = 0;
	int Version = 0;
	unsigned short ID = 0;
	unsigned char ucData[7] = {0};
	char id_str[5];
	/*读取配置寄存器中的ID和版本号*/
	iError = ReadMultiReg(ptGt9271Device, GT_PID_REG, ucData, 6);
	if (iError)
	{
		dev_err(&ptGt9271Device->ptClientIIC->dev, "Unable to read PID.\n");
		return iError;
	}
	/*前四个寄存器为ID*/
	memcpy(id_str, ucData, 4);
	id_str[4] = 0;
	/*字符串转为10进制*/
	if (kstrtou16(id_str, 10, &ID))
		ID = 0x1001;
	/*从一个 data 的偏移位置为 4 的位置（即从第五个字节开始）读取一个 16 位的小端序*/
	Version = get_unaligned_le16(&ucData[4]);
	/*输出设备信息到系统日志中*/
	dev_info(&ptGt9271Device->ptClientIIC->dev, "ID %d, version: %04x\n", ID, Version);

	iError = ReadMultiReg(ptGt9271Device, GT_9271_CFGS_REG, ucData, 7);
	if (iError)
	{
		dev_err(&ptGt9271Device->ptClientIIC->dev, "Unable to read configs.\n");
		return iError;
	}

	ptGt9271Device->iXMax     = ucData[1] + (ucData[2] << 8); 
	ptGt9271Device->iYMax     = ucData[3] + (ucData[4] << 8); 
	ptGt9271Device->iTouchNum = ucData[5] & 0X0F;
	ptGt9271Device->iIrqType  = ucData[6] & 0X03;

	printk("iXMax: %d, iYMax: %d, iTouchNum: %d, TRIGGER: 0x%02x", ptGt9271Device->iXMax, ptGt9271Device->iYMax,\
	ptGt9271Device->iTouchNum,ptGt9271Device->iIrqType);
	return 0;
}
/*Gt9271复位*/
static int Gt9271_Reset(PT_Gt9271Device ptGt9271Device,struct i2c_client *ptClient)
{
	int iError;
	/*申请复位IO*/
	if(gpio_is_valid(ptGt9271Device->iResetPin))
	{
		/* 申请复位IO，并且默认输出高电平 */
		iError = devm_gpio_request_one(&ptClient->dev,g_tGt9271.iResetPin,GPIOF_OUT_INIT_HIGH,"gt9271_reset");
		if(iError)
		{
			printk("devm_gpio_request_one gt9271_reset error!\n");
			return iError;
		}
	}
	/*申请中断IO*/
	if(gpio_is_valid(ptGt9271Device->iIrqPin))
	{
		/* 申请复位IO，并且默认输出低电平 */
		iError = devm_gpio_request_one(&ptClient->dev,g_tGt9271.iIrqPin,GPIOF_OUT_INIT_HIGH,"gt9271_irq");
		if(iError)
		{
			printk("devm_gpio_request_one gt9271_irq error!\n");
			return iError;
		}
	}
	/*初始化Gt9271,设置器件地址为0x28*/
	gpio_set_value(ptGt9271Device->iResetPin,0);
	msleep(10);
	gpio_set_value(ptGt9271Device->iResetPin,1);
	msleep(10);
	gpio_set_value(ptGt9271Device->iIrqPin, 0);   	 /* 拉低INT引脚 */
	msleep(50);
	gpio_direction_input(ptGt9271Device->iIrqPin);
	

	return 0;
}
/*触摸屏中断服务函数,GT9271 每个扫描周期均会通过 INT 脚发出脉冲信号*/
static irqreturn_t TouchSreenHandler(int irq,void *ptDevice)
{
	int iTouchNum = 0;
	int id = 0;
	int iInputX, iInputY;
	unsigned char ucData;
	unsigned char ucTouchData[5] ;
	PT_Gt9271Device dev = (PT_Gt9271Device) ptDevice;


	/*得到触摸点数*/
	ReadMultiReg(dev,GT_GSTID_REG,&ucData,1);
	if(ucData == 0x00)							/* 没有触摸数据，直接返回 */
	{
		goto fail;
	}
	else
	{
		iTouchNum = ucData & 0x0f;    			/*按下的触摸点数*/
	}
	/*多点触摸时，GT9271无法检测是哪个触摸点被松开或者按下，*/
	if (iTouchNum)         /* 单点触摸按下 */
	{
		ReadMultiReg(dev, GT_TP1_REG, ucTouchData, 5);
		id = ucTouchData[0] & 0x0F;
		if (id == 0)
		{
			iInputX = ucTouchData[1] | (ucTouchData[2] << 8);
			iInputY = ucTouchData[3] | (ucTouchData[4] << 8);

			input_mt_slot(dev->ptInput, id);
			input_mt_report_slot_state(dev->ptInput, MT_TOOL_FINGER, true);
			input_report_abs(dev->ptInput, ABS_MT_POSITION_X, iInputX);
			input_report_abs(dev->ptInput, ABS_MT_POSITION_Y, iInputY);
		}
	}
	else if (iTouchNum == 0)
	{ /* 单点触摸释放 */
		input_mt_slot(dev->ptInput, id);
		input_mt_report_slot_state(dev->ptInput, MT_TOOL_FINGER, false);
	}

	input_mt_report_pointer_emulation(dev->ptInput, true);
    input_sync(dev->ptInput);
  
	ucData = 0x00;   /* 向0X814E寄存器写0 */    				
    WriteMultiReg(dev, GT_GSTID_REG, &ucData, 1);


fail:
	return IRQ_HANDLED;

}
/*设备与驱动匹配成功时，该函数执行，其中ptClient和ptDeviceId由I2C设备传入*/
static int Gt9271_Probe(struct i2c_client *ptClient, const struct i2c_device_id *ptDeviceId)
{
	int iError;
	unsigned char ucData;
	/*1、得到设备树中描述的i2c设备*/
	g_tGt9271.ptClientIIC = ptClient;

	/*2、获取设备树中的中断和复位引脚*/
	g_tGt9271.iIrqPin   = of_get_named_gpio(ptClient->dev.of_node,"interrupt-gpios",0);
	g_tGt9271.iResetPin = of_get_named_gpio(ptClient->dev.of_node,"reset-gpios",0);

	/*3、硬复位gt9271并设置IIC地址*/
	iError = Gt9271_Reset(&g_tGt9271,ptClient);
	if(iError)
	{
		printk("Gt9271_Reset error\n");
		goto fail;
	}
	/*4、软复位*/
	ucData = 0x02;
	WriteMultiReg(&g_tGt9271,GT_CTRL_REG,&ucData,1);
	mdelay(100);
	ucData = 0x00;
	WriteMultiReg(&g_tGt9271,GT_CTRL_REG,&ucData,1);
	mdelay(100);

	/*5、读取固件配置信息*/
	iError = ReadFirmware(&g_tGt9271);
	if(iError)
	{
		printk("ReadFirmware error\n");
		goto fail;
	}
	/*6、input设备注册*/
	g_tGt9271.ptInput = devm_input_allocate_device(&ptClient->dev);
	if (!g_tGt9271.ptInput)
	{
		iError = -ENOMEM;
		printk("devm_input_allocate_device error\n");
		goto fail;
	}
	g_tGt9271.ptInput->name       = ptClient->name;
	g_tGt9271.ptInput->id.bustype = BUS_I2C;
	g_tGt9271.ptInput->dev.parent = &ptClient->dev;
	/*设置输入事件类型*/
	__set_bit(EV_KEY, g_tGt9271.ptInput->evbit);		/*按键事件*/
	__set_bit(EV_ABS, g_tGt9271.ptInput->evbit);		/*绝对坐标*/	
	__set_bit(BTN_TOUCH, g_tGt9271.ptInput->keybit);	/*触摸事件*/
	/*设置坐标轴参数*/
	input_set_abs_params(g_tGt9271.ptInput, ABS_X, 0, g_tGt9271.iXMax, 0, 0);            /*设置X轴绝对坐标轴参数*/
	input_set_abs_params(g_tGt9271.ptInput, ABS_Y, 0, g_tGt9271.iYMax, 0, 0);
	input_set_abs_params(g_tGt9271.ptInput, ABS_MT_POSITION_X,0, g_tGt9271.iXMax, 0, 0); /*设置多点触摸X轴绝对坐标轴参数*/
	input_set_abs_params(g_tGt9271.ptInput, ABS_MT_POSITION_Y,0, g_tGt9271.iYMax, 0, 0);	
	/*初始化多点触摸设备*/
	iError = input_mt_init_slots(g_tGt9271.ptInput, MAX_SUPPORT_POINTS, 0);
	if (iError) {
		printk("input_mt_init_slots error\n");
		goto fail;
	}
	/*注册输入设备*/
	iError = input_register_device(g_tGt9271.ptInput);
	if (iError) {
		printk("input_register_device error\n");
		goto fail;
	}

	/*7、初始化中断*/
	iError = devm_request_threaded_irq(&ptClient->dev , ptClient->irq , NULL , TouchSreenHandler ,\
										ucIrqTable[g_tGt9271.iIrqType] | IRQF_ONESHOT,ptClient->name,&g_tGt9271);
	printk("g_tGt9271.iIrqPin: %d   ptClient->irq: %d \n",g_tGt9271.iIrqPin,ptClient->irq);							
	if (iError) {
		printk("devm_request_threaded_irq error\n");
		goto fail;
	}
	fail:
		return iError;

}
static int Gt9271_Remove(struct i2c_client *client)
{
	input_unregister_device(g_tGt9271.ptInput);
	return 0;
}

/*GT9271无设备树时匹配表*/
static const struct i2c_device_id tGt9271_DeviceId[] = {
	{"goodix,gt9271",0,},
	{},
};
/*GT9271 设备树匹配表*/
static const struct of_device_id tGt9271_MatchTable[] = {
	{.compatible = "goodix,gt9271",},
	{},
};
static struct i2c_driver tGt9271Driver = {
	.driver = {
		.owner = THIS_MODULE,
		.name  = "goodix_gt9271",
		.of_match_table = tGt9271_MatchTable,
	},
	.id_table = tGt9271_DeviceId,
	.probe  = Gt9271_Probe,
	.remove = Gt9271_Remove,
};

module_i2c_driver(tGt9271Driver);
// static int __init gt9271_init(void)
// {
// 	return i2c_add_driver(&tGt9271Driver);
// }
// static void __exit gt9271_exit(void)
// {
// 	i2c_del_driver(&tGt9271Driver);
// }
// module_init(gt9271_init);
// module_exit(gt9271_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Destiny");

